home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1995 February: Tool Chest / Dev.CD Feb 95 / Dev.CD Feb 95.toast / Tool Chest / Development Tools & Languages / Dylan Related / Mindy-1.1 (sources only) / mindy-1.1 / libraries / dylan / range.dylan < prev    next >
Encoding:
Text File  |  1994-08-23  |  33.2 KB  |  1,088 lines  |  [TEXT/ttxt]

  1. module: Dylan
  2. rcs-header: $Header: range.dylan,v 1.5 94/08/22 15:24:23 nkramer Exp $
  3.  
  4. //======================================================================
  5. //
  6. // Copyright (c) 1994  Carnegie Mellon University
  7. // All rights reserved.
  8. // 
  9. // Use and copying of this software and preparation of derivative
  10. // works based on this software are permitted, including commercial
  11. // use, provided that the following conditions are observed:
  12. // 
  13. // 1. This copyright notice must be retained in full on any copies
  14. //    and on appropriate parts of any derivative works.
  15. // 2. Documentation (paper or online) accompanying any system that
  16. //    incorporates this software, or any part of it, must acknowledge
  17. //    the contribution of the Gwydion Project at Carnegie Mellon
  18. //    University.
  19. // 
  20. // This software is made available "as is".  Neither the authors nor
  21. // Carnegie Mellon University make any warranty about the software,
  22. // its performance, or its conformity to any specification.
  23. // 
  24. // Bug reports, questions, comments, and suggestions should be sent by
  25. // E-mail to the Internet address "gwydion-bugs@cs.cmu.edu".
  26. //
  27. //======================================================================
  28. //
  29. // This file contains definitions of classes and functions for the
  30. // Dylan range collection class.  Ranges represent linear arithmetic
  31. // sequences, which may be infinitely long.
  32. //
  33.  
  34.  
  35.  
  36. /* Dylan Range Class Definition
  37.  
  38.    Objects of the class <range> represent linear arithmetic sequences
  39.    (here sequence is the mathematical term as well as the collection
  40.    term).  Ranges are special collections because they may be
  41.    infinitely long.
  42.  
  43.    A range is defined by six keyword arguments to the constructor
  44.    function RANGE -- from:, by:, to:, above:, below:, and size:.  Any
  45.    of these may be given or omitted; the behavior of the range depends
  46.    on the combination of keywords given.  The FROM and BY keywords
  47.    have default values 0 and 1 respectively.  The range created begins
  48.    at FROM and increases by an increment of BY.
  49.  
  50.    The endpoint of the range is determined by the combination of the
  51.    to:, above:, below:, and size: keywords.  TO is an inclusive bound
  52.    independent of the direction of the range.  ABOVE is an exclusive
  53.    lower bound and BELOW is and exclusive upper bound.  The range will
  54.    have no more than SIZE elements.
  55.  
  56.    The range representation used in this code is simplified so that
  57.    only the from, by, and a size value need to be stored.  The
  58.    original representation (using TO, ABOVE, or whatever) is
  59.    translated to this representation by the function
  60.    COMPUTE-RANGE-SIZE.
  61.  
  62. */
  63.  
  64. // <range> -- public
  65. // 
  66. // The <range> abstract class represents ranges (linear arithmetic
  67. // sequences).  The class has slots to store the FROM and BY
  68. // parameters of the range and a virtual slot RANGE-DIRECTION.
  69. // 
  70. // The concrete subclasses that implement the range protocol are
  71. // <bounded-range> and <unbounded-range>.
  72. //
  73. define abstract class <range> (<sequence>)
  74.    slot range-from :: <real>,
  75.       init-value: 0,
  76.       init-keyword: from:;
  77.    slot range-by :: <real>,
  78.       init-value: 1,
  79.       init-keyword: by:;
  80.    virtual slot range-direction,
  81.       setter: #f;
  82. end class;
  83.  
  84.  
  85. // range-direction -- internal
  86. // 
  87. // This implements the virtual slot RANGE-DIRECTION.  Returns the
  88. // direction of the range.  If the range increment BY is positive, the
  89. // range has the direction #"increasing", if negative, #"decreasing",
  90. // and if zero, #"none".
  91. //
  92. define method range-direction (range :: <range>)
  93.       => direction :: <symbol>;
  94.    let r-by = range.range-by;
  95.    case
  96.       r-by = 0 => #"none";
  97.       r-by > 0 => #"increasing";
  98.       r-by < 0 => #"decreasing";
  99.    end case;
  100. end method;
  101.  
  102.  
  103. // <unbounded-range> -- extremely internal
  104. // 
  105. // Class to represent unbounded (infinite) ranges.
  106. // 
  107. // MAKE should never be called on <unbounded-range> except for the few
  108. // places in the range constructor.  Please use RANGE instead.
  109. //
  110. define class <unbounded-range> (<range>) end class;
  111.  
  112.  
  113. // <bounded-range> -- extremely internal
  114. // 
  115. // Class to represent bounded (finite) ranges.  This class adds a size
  116. // slot to the <range> class.
  117. // 
  118. // MAKE should never be called on <bounded-range> except for the few
  119. // places in the range constructor.  Please use RANGE instead.
  120. //
  121. define class <bounded-range> (<range>)
  122.    slot range-size :: <integer>,
  123.       required-init-keyword: size:;
  124. end class;
  125.  
  126.  
  127.  
  128. /* Range Utility Functions
  129.  
  130.    This section contains functions that are used to do the computation
  131.    needed to set up a range.  Such computations include figuring out
  132.    what the size of a range should be given its FROM, BY, TO, ABOVE,
  133.    BELOW, and SIZE parameters.
  134.  
  135. */
  136.  
  137. // compute-range-size -- internal
  138. // 
  139. // This function translates the (from, by, to, above, below, size)
  140. // representation of the user to the (from, by, size) (bounded) or
  141. // (from, by) (unbounded) internal representation.
  142. // 
  143. // The size returned by COMPUTE-RANGE-SIZE is the smallest range size
  144. // such that:
  145. // 1) the first (if any) element of the range is FROM and its
  146. //    increment is BY
  147. // 2) the range has no element less than ABOVE or greater than BELOW
  148. // 3) the range has no element greater than TO + BY if BY is positive,
  149. //    or no element less than TO + BY if BY is negative
  150. // 4) the size of the range is no greater than SIZE
  151. // 
  152. // Size limitations for each of the arguments are computed.  Valid
  153. // sizes (sizes not #f) are taken.
  154. // 
  155. // If there are no valid sizes, #f is returned.  (Everywhere in this
  156. // implementation of ranges, a size of #f denotes an unbounded range.)
  157. // If valid sizes exists the maximum of 0 and the minimum of the valid
  158. // sizes is returned.
  159. //
  160. define method compute-range-size (r-from :: <real>,
  161.                   r-by :: <real>,
  162.                   r-to :: union (singleton (#f), <real>),
  163.                   r-above :: union (singleton (#f), <real>),
  164.                   r-below :: union (singleton (#f), <real>),
  165.                   r-size :: union (singleton (#f), <integer>))
  166.       => size :: union (singleton (#f), <integer>);
  167.    let to-size = r-to & compute-to-size (r-from, r-by, r-to);
  168.    let above-size = r-above & compute-above-size (r-from, r-by, r-above);
  169.    let below-size = r-below & compute-below-size (r-from, r-by, r-below);
  170.    let size-size = r-size;
  171.  
  172.    let valid-sizes =
  173.       choose (identity, list (to-size, above-size, below-size, size-size));
  174.  
  175.    if (empty? (valid-sizes))
  176.       #f
  177.    else
  178.       max (0, apply (min, valid-sizes))
  179.    end if;
  180. end method;
  181.  
  182.  
  183. // compute-to-size -- internal
  184. // 
  185. // Computes the limiting size of a TO argument to RANGE.  This size is
  186. // one plus the nearest integer larger than
  187. // 
  188. //         (BOUND - START) / INCREMENT
  189. // 
  190. // (See also APPROXIMATE-RANGE-KEY.  The TO size limit is essentially
  191. // the larger approximate key for BOUND (plus 1).)
  192. // 
  193. // (The <integer> method is slightly optimized for case where the
  194. // increment is +1 or -1.)
  195. //
  196. define method compute-to-size (start :: <integer>,
  197.                    increment :: <integer>,
  198.                    bound :: <integer>)
  199.       => to-size :: union (singleton (#f), <integer>);
  200.    select (increment by \=)
  201.       0 =>
  202.      #f;
  203.       1 =>
  204.      bound - start + 1;
  205.       -1 =>
  206.      -(bound - start) + 1;
  207.       otherwise =>
  208.      ceiling/ (bound - start, increment) + 1;
  209.    end select;
  210. end method;
  211. //
  212. define method compute-to-size (start :: <real>,
  213.                    increment :: <real>,
  214.                    bound :: <real>)
  215.       => to-size :: union (singleton (#f), <integer>);
  216.    select (increment by \=)
  217.       0 =>
  218.      #f;
  219.       otherwise =>
  220.      ceiling/ (bound - start, increment) + 1;
  221.    end select;
  222. end method;
  223.  
  224.  
  225. // compute-above-size -- internal
  226. // 
  227. // Computes the limiting size of an ABOVE argument to RANGE.  This
  228. // size is the nearest integer larger than
  229. // 
  230. //         (BOUND - START) / INCREMENT
  231. // 
  232. // if the increment is negative (the range is decreasing toward the
  233. // ABOVE bound.)
  234. // 
  235. // If the range is not decreasing, then if START if above ABOVE, #f is
  236. // returned (no limiting size).  But if START is below ABOVE, 0 is
  237. // returned.
  238. //
  239. define method compute-above-size (start :: <integer>,
  240.                   increment :: <integer>,
  241.                   bound :: <integer>)
  242.       => above-size :: union (singleton (#f), <integer>);
  243.    if (negative? (increment))
  244.       if (increment = -1)
  245.      -(bound - start)
  246.       else
  247.      ceiling/ (bound - start, increment)
  248.       end if;
  249.    else
  250.       if (bound < start)
  251.      #f
  252.       else
  253.      0
  254.       end if;
  255.    end if;
  256. end method;
  257. //
  258. define method compute-above-size (start :: <real>,
  259.                   increment :: <real>,
  260.                   bound :: <real>)
  261.       => above-size :: union (singleton (#f), <integer>);
  262.    if (negative? (increment))
  263.       ceiling/ (bound - start, increment)
  264.    else
  265.       if (bound < start)
  266.      #f
  267.       else
  268.      0
  269.       end if;
  270.    end if;
  271. end method;
  272.  
  273.  
  274. // compute-below-size -- internal
  275. //
  276. // Computes the limiting size of an BELOW argument to RANGE.  This size is
  277. // the nearest integer larger than
  278. // 
  279. //         (BOUND - START) / INCREMENT
  280. // 
  281. // if the increment is positive (the range is increasing toward the
  282. // BELOW bound.)
  283. // 
  284. // If the range is not increasing, then if START if below BELOW, #f is
  285. // returned (no limiting size).  But if START is above BELOW, 0 is
  286. // returned.
  287. //
  288. define method compute-below-size (start :: <integer>,
  289.                   increment :: <integer>,
  290.                   bound :: <integer>)
  291.       => below-size :: union (singleton (#f), <integer>);
  292.    if (positive? (increment))
  293.       if (increment = 1)
  294.      bound - start
  295.       else
  296.      ceiling/ (bound - start, increment)
  297.       end if;
  298.    else
  299.       if (bound > start)
  300.      #f
  301.       else
  302.      0
  303.       end if;
  304.    end if;
  305. end method;
  306. //
  307. define method compute-below-size (start :: <real>,
  308.                   increment :: <real>,
  309.                   bound :: <real>)
  310.       => below-size :: union (singleton (#f), <integer>);
  311.    if (positive? (increment))
  312.       if (increment = 1)
  313.      bound - start
  314.       else
  315.      ceiling/ (bound - start, increment)
  316.       end if;
  317.    else
  318.       if (bound > start)
  319.      #f
  320.       else
  321.      0
  322.       end if;
  323.    end if;
  324. end method;
  325.  
  326.  
  327. // approximate-range-key -- internal
  328. //
  329. // Returns the key of the element of RANGE nearest to ELEMENT.  The
  330. // approximate key for a number N is the integer nearest
  331. // 
  332. //             (N - FROM) / BY
  333. //
  334. define method approximate-range-key (range :: <range>, element :: <real>)
  335.       => key :: <integer>;
  336.    round/ (element - range.range-from, range.range-by)
  337. end method;
  338.  
  339.  
  340.  
  341. /* Range Functions
  342.  
  343.    This section includes the special range constructor RANGE, and
  344.    other functions special to the implementation of ranges, such as
  345.    ELEMENT, and the method for BINARY=.
  346.  
  347. */
  348.  
  349. // range -- public
  350. // 
  351. // RANGE is the constructor for ranges.  It accepts six keywords --
  352. // from:, by:, to:, above:, below:, and size:.  It uses
  353. // COMPUTE-RANGE-SIZE to find the appropriate size for the new range.
  354. // If this size is #f an unbounded range is created, otherwise a
  355. // bounded range is made.
  356. //
  357. define constant range =
  358. method (#key from: r-from = 0, by: r-by = 1,
  359.     to: r-to = #f, above: r-above = #f, below: r-below = #f,
  360.     size: r-size = #f)
  361.       => new-range :: <range>;
  362.    let range-size =
  363.       compute-range-size (r-from, r-by, r-to, r-above, r-below, r-size);
  364.    if (range-size)
  365.       make (<bounded-range>, from: r-from, by: r-by, size: range-size);
  366.    else
  367.       make (<unbounded-range>, from: r-from, by: r-by);
  368.    end if;
  369. end method;
  370.  
  371.  
  372. // make -- public
  373. // 
  374. // The MAKE method for abstract class <range> applies RANGE, the range
  375. // constructor, to the keyword arguments.  This produces an instance
  376. // of one of the concrete subclasses <bounded-range> or
  377. // <unbounded-range>.
  378. //
  379. define method make (class-to-make == <range>, #rest keys, #all-keys)
  380.       => <range>;
  381.    apply (range, keys);
  382. end method;
  383.  
  384.  
  385. // element -- public
  386. // 
  387. // Returns the element of the range corresponding to KEY.  This
  388. // element is found using FROM + KEY * BY.  If KEY is out of the
  389. // bounds of the range, the default is returned or an error is
  390. // signalled.
  391. //
  392. define method element (range :: <bounded-range>, key :: <integer>,
  393.                        #key default = no-default)
  394.       => <real>;
  395.    case
  396.       (key >= 0) & (key < range.range-size) =>
  397.          range.range-from + (key * range.range-by);
  398.       (default == no-default) =>
  399.          error ("No such element in %=: %d", range, key);
  400.       otherwise =>
  401.          default;
  402.    end case;
  403. end method;
  404. //
  405. define method element (range :: <unbounded-range>, key :: <integer>,
  406.                        #key default = no-default)
  407.       => <real>;
  408.    case
  409.       (key >= 0) =>
  410.          range.range-from + (key * range.range-by);
  411.       (default == no-default) =>
  412.          error ("No such element in %=: %d", range, key);
  413.       otherwise =>
  414.          default;
  415.    end case;
  416. end method;
  417.  
  418.  
  419. // = -- public
  420. // 
  421. // Ranges are = if their beginning points, increments, and sizes are
  422. // equal.
  423. //
  424. define method \= (range1 :: <range>, range2 :: <range>)
  425.       => equal? :: <boolean>;
  426.    range1.range-from = range2.range-from
  427.       & range1.range-by = range2.range-by
  428.       & range1.range-size = range2.range-size;
  429. end method;
  430.  
  431.  
  432.  
  433. /* Iteration Protocol
  434.  
  435.    Iteration states for ranges are simply the integer keys, since we
  436.    have an efficient way of calculating any element of the range.
  437.  
  438.    For bounded ranges we have to check the state against the size of the
  439.    range.  Iteration over unbounded ranges does not terminate (i.e.
  440.    NEXT-STATE never returns #f).
  441.  
  442. */
  443.  
  444. // forward-iteration-protocol -- public
  445. // 
  446. define method forward-iteration-protocol (range :: <bounded-range>)
  447.       => (initial-state          :: <object>,
  448.       limit                  :: <object>,
  449.       next-state             :: <function>,
  450.       finished-state?        :: <function>,
  451.       current-key            :: <function>,
  452.       current-element        :: <function>,
  453.       current-element-setter :: <function>,
  454.       copy-state?            :: <function>);
  455.    let initial-state = 0;
  456.    let limit = range.range-size;
  457.    local method next-state (r :: <range>, s :: <integer>)
  458.         s + 1
  459.      end method;
  460.    local method finished-state? (r :: <range>, s :: <integer>, l :: <integer>)
  461.         s = l
  462.      end method;
  463.    local method current-key (r :: <range>, s :: <integer>)
  464.         s
  465.      end method;
  466.    local method current-element (r :: <range>, s :: <integer>)
  467.         r[s];
  468.      end method;
  469.    local method current-element-setter (r :: <range>, s :: <integer>, value)
  470.             error ("CURRENT-ELEMENT-SETTER not applicable for <range>");
  471.      end method;
  472.    local method copy-state (r :: <range>, s :: <integer>)
  473.         s
  474.      end method;
  475.    values (initial-state, limit, next-state, finished-state?, current-key,
  476.        current-element, current-element-setter, copy-state);
  477. end method;
  478. //
  479. define method forward-iteration-protocol (range :: <unbounded-range>)
  480.       => (initial-state :: <object>, limit :: <object>,
  481.       next-state :: <function>, finished-state? :: <function>,
  482.       current-key :: <function>, current-element :: <function>,
  483.       current-element-setter :: <function>, copy-state? :: <function>);
  484.    let initial-state = 0;
  485.    let limit = #f;
  486.    local method next-state (r :: <range>, s :: <integer>)
  487.         s + 1
  488.      end method;
  489.    local method finished-state? (r :: <range>, s :: <integer>, l)
  490.         #f
  491.      end method;
  492.    local method current-key (r :: <range>, s :: <integer>)
  493.         s
  494.      end method;
  495.    local method current-element (r :: <range>, s :: <integer>)
  496.         r[s];
  497.      end method;
  498.    local method current-element-setter (r :: <range>, s :: <integer>, value)
  499.             error ("CURRENT-ELEMENT-SETTER not applicable for <range>");
  500.      end method;
  501.    local method copy-state (r :: <range>, s :: <integer>)
  502.         s
  503.      end method;
  504.    values (initial-state, limit, next-state, finished-state?, current-key,
  505.        current-element, current-element-setter, copy-state);
  506. end method;
  507.  
  508.  
  509.  
  510. /* Collection Function Methods
  511.  
  512.    The collection functions which have methods specialized for ranges
  513.    are SIZE, CLASS-FOR-COPY, EMPTY?, and MEMBER?.  These methods are
  514.    defined in this section.
  515.  
  516.    Ranges use the default methods for the collection functions DO,
  517.    MAP, ANY?, EVERY?, and FIND-KEY.
  518.  
  519.    Ranges have no methods for SIZE-SETTER because they are not
  520.    stretchy.  Ranges do not have methods for MAP-AS, MAP-INTO,
  521.    REPLACE-ELEMENTS!, and FILL! because they are not mutable.
  522.  
  523.    The methods for REDUCE and REDUCE1 for unbounded ranges signal an
  524.    error, since reduction over unbounded ranges will not terminate.
  525.  
  526.    Note that using some of the default methods on unbounded ranges may
  527.    cause infinite loops.  For example, uses of DO, MAP, ANY?, or
  528.    EVERY? on unbounded ranges may never terminate.  (On the other
  529.    hand, they might terminate, so we do not make this an error.)
  530.  
  531. */
  532.  
  533. // size -- public
  534. // 
  535. // SIZE for unbounded ranges returns #f.
  536. //
  537. define method sizes (range :: <bounded-range>)
  538.    range.range-size
  539. end method;
  540. //
  541. define method size (range :: <unbounded-range>)
  542.    #f
  543. end method;
  544.  
  545.  
  546. // class-for-copy -- public
  547. // 
  548. define method class-for-copy (range :: <range>)
  549.    <list>
  550. end method;
  551.  
  552.  
  553. // empty? -- public
  554. // 
  555. // A bounded range is empty if the size is zero.  An unbounded range
  556. // can never be empty.
  557. //
  558. define method empty? (range :: <bounded-range>)
  559.    range.range-size = 0
  560. end method;
  561. //
  562. define method empty? (range :: <unbounded-range>)
  563.    #f
  564. end method;
  565.  
  566.  
  567. // reduce reduce1
  568. // 
  569. // Trying to reduce an unbounded range will not terminate.
  570. //
  571. define method reduce (procedure :: <function>, initial-value,
  572.               range :: <unbounded-range>)
  573.    error ("REDUCE not applicable for unbounded <range>");
  574. end method;
  575. //
  576. define method reduce1 (procedure :: <function>, range :: <unbounded-range>)
  577.    error ("REDUCE1 not applicable for unbounded <range>");
  578. end method;
  579.  
  580.  
  581. // member? -- public
  582. // 
  583. // MEMBER? for ranges must terminate even if the range is unbounded.
  584. // The way to check to see if a number N is an element of a range is
  585. // to compute its approximate key in the range.  Then if the
  586. // approximate key is within the bounds of the range and if the value
  587. // tests with the element at the key, MEMBER? returns #t.
  588. //
  589. define method member? (value :: <real>, range :: <bounded-range>,
  590.                #key test = \==)
  591.    let approximate-position =
  592.       if (range.range-by = 0)
  593.      0
  594.       else
  595.      approximate-range-key (range, value)
  596.       end if;
  597.  
  598.    if (approximate-position >= 0 & approximate-position < range.range-size)
  599.       test (value, range[approximate-position])
  600.    else
  601.       #f
  602.    end if;
  603. end method;
  604. //
  605. define method member? (value :: <real>, range :: <unbounded-range>,
  606.                #key test = \==)
  607.    let approximate-position =
  608.       if (range.range-by = 0)
  609.      0
  610.       else
  611.      approximate-range-key (range, value)
  612.       end if;
  613.  
  614.    if (approximate-position >= 0)
  615.       test (value, range[approximate-position])
  616.    else
  617.       #f
  618.    end if;
  619. end method;
  620.  
  621.  
  622.  
  623. /* Sequence Function Methods
  624.  
  625.    The sequence functions which have methods specialized for ranges
  626.    are INTERSECTION, COPY-SEQUENCE, REVERSE, and LAST.  These methods
  627.    are defined in this section.
  628.  
  629.    Ranges use the default methods for the sequence functions ADD(!),
  630.    ADD-NEW(!), REMOVE(!), CHOOSE, CHOOSE-BY, UNION,
  631.    REMOVE-DUPLICATES(!), CONCATENATE, REPLACE-SUBSEQUENCE!, SORT(!),
  632.    FIRST, SECOND, THIRD, and SUBSEQUENCE-POSITION.
  633.  
  634.    Ranges do not have methods for CONCATENATE-AS, and FIRST- SECOND-
  635.    THIRD- LAST-SETTER because they are not mutable.
  636.  
  637.    The methods for ADD, ADD-NEW, CHOOSE, REMOVE-DUPLICATES, REVERSE,
  638.    SORT, and LAST for unbounded ranges signal an error, since any of
  639.    these over unbounded ranges will not terminate.
  640.  
  641.    Note that using some of the default methods on unbounded ranges may
  642.    cause infinite loops.  For example, uses of CHOOSE-BY, UNION,
  643.    CONCATENATE, and REPLACE-SUBSEQUENCE! on unbounded ranges may never
  644.    terminate.
  645.  
  646. */
  647.  
  648. // add
  649. //
  650. define method add (range :: <unbounded-range>, new)
  651.    error ("ADD not applicable for unbounded <range>");
  652. end method;
  653.  
  654.  
  655. // add-new
  656. //
  657. define method add-new (range :: <unbounded-range>, new, #key test)
  658.    error ("ADD-NEW not applicable for unbounded <range>");
  659. end method;
  660.  
  661.  
  662. // choose
  663. //
  664. define method choose (predicate :: <function>, range :: <unbounded-range>)
  665.    error ("CHOOSE not applicable for unbounded <range>");
  666. end method;
  667.  
  668.  
  669. // intersection -- public
  670. // 
  671. // Range intersection is quite complicated, so the implementation is
  672. // included in its own section below.
  673.  
  674.  
  675. // remove-duplicates
  676. //
  677. define method remove-duplicates (range :: <unbounded-range>, #key test)
  678.    error ("REMOVE-DUPLICATES not applicable for unbounded <range>");
  679. end method;
  680.  
  681.  
  682. // copy-sequence -- public
  683. // 
  684. // Returns a range which is a copy of the source range.  The START and
  685. // END keywords specify at which elements of the range copying should
  686. // begin and end.
  687. // 
  688. // For bounded ranges, correct values for COPY-START and COPY-END are
  689. // found with respect to the range, and RANGE is called with the right
  690. // length and other parameters from the original range.
  691. // 
  692. // For unbounded ranges, a bounded range is returned if END is
  693. // supplied, and an unbounded range if not.
  694. //
  695. define method copy-sequence (source :: <bounded-range>,
  696.                  #key start: copy-start = 0, end: copy-end)
  697.    let r-size = source.range-size;
  698.    let r-from = source.range-from;
  699.    let r-by = source.range-by;
  700.    let copy-start = if (copy-start >= 0)
  701.                copy-start
  702.             else
  703.                0
  704.             end if;
  705.    let copy-end = if (copy-end)
  706.              copy-end
  707.           else
  708.              r-size
  709.           end if;
  710.    if (copy-start > copy-end) 
  711.      error("End: (%=) is smaller than start: (%=)", copy-start, copy-end);
  712.    end if;
  713.  
  714.    case
  715.       copy-start > r-size =>
  716.      range (size: 0);
  717.       copy-end > r-size =>
  718.      range (from: source[copy-start], by: r-by,
  719.         size: r-size - copy-start);
  720.       otherwise =>
  721.      range (from: source[copy-start], by: r-by,
  722.         size: copy-end - copy-start);
  723.    end case;
  724. end method;
  725. //
  726. define method copy-sequence (source :: <unbounded-range>,
  727.                  #key start: copy-start = 0, end: copy-end)
  728.    let r-from = source.range-from;
  729.    let r-by = source.range-by;
  730.    let copy-start = if (copy-start >= 0)
  731.                copy-start
  732.             else
  733.                0
  734.             end if;
  735.    if (copy-end)
  736.       range (from: source[copy-start], by: r-by,
  737.          size: copy-end - copy-start);
  738.    else
  739.       range (from: source[copy-start], by: r-by);
  740.    end if;
  741. end method;
  742.  
  743.  
  744. // reverse -- public
  745. // 
  746. // For bounded ranges REVERSE returns a new range from: the last
  747. // element of the original range, by: the negative of the original by,
  748. // with size: the size of the original range.
  749. // 
  750. // Unbounded ranges cannot be reversed.p
  751. //
  752. define method reverse (range-to-reverse :: <bounded-range>)
  753.    range (from: last (range-to-reverse, default: range-to-reverse.range-from),
  754.       by: negative (range-to-reverse.range-by),
  755.       size: range-to-reverse.range-size);
  756. end method;
  757. //
  758. define method reverse (range :: <unbounded-range>)
  759.    error ("REVERSE not applicable for unbounded <range>");
  760. end method;
  761.  
  762.  
  763. // reverse! -- public
  764. // 
  765. // For bounded ranges, REVERSE! sets RANGE-FROM to the last element of
  766. // the range and RANGE-BY to the negative of the original by, and
  767. // returns the range.
  768. // 
  769. // Unbounded ranges cannot be REVERSED!.
  770. //
  771. define method reverse! (range :: <bounded-range>)
  772.    range.range-from := last (range, default: range.range-from);
  773.    range.range-by := negative (range.range-by);
  774.    range
  775. end method;
  776. //
  777. define method reverse! (range :: <unbounded-range>)
  778.    error ("REVERSE! not applicable for unbounded <range>");
  779. end method;
  780.  
  781.  
  782. // sort
  783. //
  784. define method sort (range :: <unbounded-range>, #key test, stable)
  785.    error ("SORT not applicable for unbounded <range>");
  786. end method;
  787.  
  788.  
  789. // last -- public
  790. // 
  791. // Returns the element at RANGE-SIZE - 1.  Signals an error for
  792. // unbounded ranges.
  793. //
  794. define method last (range :: <bounded-range>, #key default = no-default)
  795.    element (range, range.range-size - 1, default: default)
  796. end method;
  797. //
  798. define method last (range :: <unbounded-range>, #key default)
  799.    error ("LAST not applicable for unbounded <range>");
  800. end method;
  801.  
  802.  
  803.  
  804. /*
  805.               Range Intersection
  806.  
  807.    INTERSECTION for ranges is required to return even for unbounded
  808.    ranges.  So the algorithm used for range intersection must be able
  809.    to find an intersection for unbounded ranges.  Fortunately this is
  810.    not too hard with the representation of ranges used here.
  811.  
  812.    The steps of finding the intersection of two ranges are:
  813.  
  814.    1) Find the interval in which the two ranges must intersect.  This
  815.       interval may be infinitely long in one direction.
  816.  
  817.    2) If the interval is finite, find the finite intersection of the
  818.       two ranges within that interval.
  819.  
  820.       If the interval is infinite, find the unbounded increasing or
  821.       decreasing (one or the other) intersection of the two ranges
  822.       within that interval.
  823.  
  824.    The functions to do these steps are defined below.  Step 1 is
  825.    performed by INTERSECTION-INTERVAL.  Step 2 is performed by one of
  826.    FINITE-INTERSECTION, INCREASING-INTERSECTION, or
  827.    DECREASING-INTERSECTION.
  828.  
  829. */
  830.  
  831. // intersection -- public
  832. // 
  833. // The method on sequence intersection for ranges.  If the TEST is ==
  834. // or =, INTERSECTION will produce a range as its result.  If not,
  835. // then the sequence produced is the result of the default sequence
  836. // method for ranges.
  837. //
  838. define method intersection (range1 :: <range>, range2 :: <range>,
  839.                 #next next-method, #key test = \==)
  840.       => sequence :: <sequence>;
  841.    if (test == \== | test == \=)
  842.       range-intersection (range1, range2, test: test);
  843.    else
  844.       next-method ();
  845.    end if;
  846. end method;
  847.  
  848.  
  849. // range-intersection -- internal
  850. // 
  851. // Return a new range which is the intersection of the two ranges.
  852. // 
  853. // This is done by finding the interval of intersection of the two
  854. // ranges, and calculating the either finite, infinite increasing, or
  855. // infinite decreasing intersection withing the interval.
  856. //
  857. define method range-intersection (range1 :: <range>, range2 :: <range>,
  858.                   #key test)
  859.       => range :: <range>;
  860.    let (x-from, x-to) = intersection-interval (range1, range2);
  861.    case
  862.       ~ x-from =>
  863.      decreasing-intersection (range1, range2, test: test);
  864.       ~ x-to =>
  865.      increasing-intersection (range1, range2, test: test);
  866.       otherwise =>
  867.      finite-intersection (range1, range2, test: test);
  868.    end case;
  869. end method;
  870.  
  871.  
  872. // finite-intersection -- internal
  873. // 
  874. // Returns a bounded range containing the intersection of the two
  875. // ranges.  The keys in RANGE1 of the bounds of the intersection
  876. // interval are computed.  Then all the elements of RANGE1 between
  877. // these keys which are also elements of RANGE2 are found.  A new
  878. // range beginning at the first element (if any) of elements and
  879. // ending at the last with the increment of the second - the first is
  880. // returned.
  881. //
  882. define method finite-intersection (range1 :: <range>, range2 :: <range>,
  883.                    #key test)
  884.       => range :: <bounded-range>;
  885.    let (x-from, x-to) = intersection-interval (range1, range2);
  886.    let from-key = approximate-range-key (range1, x-from);
  887.    let to-key = approximate-range-key (range1, x-to);
  888.    let intersection =
  889.       if (range1.range-direction == #"increasing")
  890.      choose (rcurry (member?, range2, test: test),
  891.          copy-sequence (range1, start: from-key, end: to-key + 1));
  892.       else
  893.      choose (rcurry (member?, range2, test: test),
  894.          copy-sequence (range1, start: to-key, end: from-key + 1));
  895.       end if;
  896.    select (intersection.size by \=)
  897.       0 =>
  898.      range (size: 0);
  899.       1 =>
  900.          range (from: intersection.first, size: 1);
  901.       otherwise =>
  902.          range (from: intersection.first, to: intersection.last,
  903.         by: intersection.second - intersection.first);
  904.    end select;
  905. end method;
  906.  
  907.  
  908. // increasing-intersection -- internal
  909. // 
  910. // Returns an unbounded increasing range containing the intersection
  911. // of the two ranges.  BY is taken to be the least common multiple of
  912. // the BYs of RANGE1 and RANGE2.  The key in RANGE1 of the lower
  913. // intersection interval bound is found, and the upper key is taken to
  914. // be the key of the lower bound + BY (because the intersection
  915. // interval has no upper bound).  (If the intersection has any
  916. // elements, there must be one within BY of the bottom of the
  917. // intersection interval.)
  918. // 
  919. // The elements of RANGE1 between these keys which are also elements
  920. // of RANGE2 are found, and a new range beginning with the first of
  921. // these (if any) and with an increment of BY is returned.
  922. //
  923. define method increasing-intersection (range1 :: <unbounded-range>,
  924.                        range2 :: <unbounded-range>,
  925.                        #key test)
  926.       => range :: <unbounded-range>;
  927.    let (x-from, x-to) = intersection-interval (range1, range2);
  928.    let x-by = lcm (range1.range-by, range2.range-by);
  929.    let from-key = approximate-range-key (range1, x-from);
  930.    let to-key = approximate-range-key (range1, x-from + 2 * x-by);
  931.    let intersection =
  932.       choose (rcurry (member?, range2, test: test),
  933.           copy-sequence (range1, start: from-key, end: to-key));
  934.    if (empty? (intersection))
  935.       range (size: 0);
  936.    else
  937.       range (from: intersection.first, by: x-by);
  938.    end if;
  939. end method;
  940.  
  941.  
  942. // decreasing-intersection -- internal
  943. // 
  944. // Returns an unbounded decreasing range containing the intersection
  945. // of the two ranges.  BY is taken to be the least common multiple of
  946. // the BYs of RANGE1 and RANGE2.  The key in RANGE1 of the upper
  947. // intersection interval bound is found, and the lower key is taken to
  948. // be the key of the upper bound + BY (because the intersection
  949. // interval has no lower bound).  (If the intersection has any
  950. // elements, there must be one within BY of the top of the
  951. // intersection interval.)
  952. // 
  953. // The elements of RANGE1 between these keys which are also elements
  954. // of RANGE2 are found, and a new range beginning with the first of
  955. // these (if any) and with an increment of BY is returned.
  956. //
  957. define method decreasing-intersection (range1 :: <unbounded-range>,
  958.                        range2 :: <unbounded-range>,
  959.                        #key test)
  960.       => range :: <unbounded-range>;
  961.    let (x-from, x-to) = intersection-interval (range1, range2);
  962.    let x-by = -lcm (-range1.range-by, -range2.range-by);
  963.    let from-key = approximate-range-key (range1, x-to + 2 * x-by);
  964.    let to-key = approximate-range-key (range1, x-to);
  965.    let intersection =
  966.       choose (rcurry (member?, range2, test: test),
  967.           copy-sequence (range1, start: to-key, end: from-key));
  968.    if (empty? (intersection))
  969.       range (size: 0);
  970.    else
  971.       range (from: intersection.first, by: x-by);
  972.    end if;
  973. end method;
  974.  
  975.  
  976. // range-directions -- internal
  977. // 
  978. // Returns a symbol denoting the respective directions of RANGE1 and
  979. // RANGE2.
  980. //
  981. define method range-directions (range1 :: <range>, range2 :: <range>)
  982.       => direction :: <symbol>;
  983.    if (range1.range-direction == #"increasing")
  984.       if (range2.range-direction == #"increasing")
  985.      #"increasing-increasing"
  986.       else
  987.      #"increasing-decreasing"
  988.       end if;
  989.    else
  990.       if (range2.range-direction == #"increasing")
  991.      #"decreasing-increasing"
  992.       else
  993.      #"decreasing-decreasing"
  994.       end if;
  995.    end if;
  996. end method;
  997.  
  998.  
  999. // intersection-interval -- internal
  1000. // 
  1001. // Returns the lower and upper bounds of the interval in which the two
  1002. // ranges intersect.
  1003. // 
  1004. // For any intersection with a bounded range, the intersection
  1005. // interval will be finite.  The first number returned is always lower
  1006. // than the second.
  1007. // 
  1008. // For two unbounded ranges, the interval of intersection may be
  1009. // infinitely long in one direction or the other.  In this case one of
  1010. // the bounds will be #f (using the convention in this code that #f
  1011. // represents an unbounded size).
  1012. //
  1013. define method intersection-interval (range1 :: <bounded-range>,
  1014.                      range2 :: <bounded-range>)
  1015.       => (x-from :: union (singleton (#f), <integer>),
  1016.       x-to :: union (singleton (#f), <integer>));
  1017.    let from1 = range1.range-from;
  1018.    let to1 = range1.last;
  1019.    let from2 = range2.range-from;
  1020.    let to2 = range2.last;
  1021.    select (range-directions (range1, range2))
  1022.       #"increasing-increasing" =>
  1023.      values (max (from1, from2), min (to1, to2));
  1024.       #"increasing-decreasing" =>
  1025.      values (max (from1, to2), min (to1, from2));
  1026.       #"decreasing-increasing" =>
  1027.      values (max (to1, from2), min (from1, to2));
  1028.       #"decreasing-decreasing" =>
  1029.      values (max (to1, to2), min (from1, from2));
  1030.    end select;
  1031. end method;
  1032. //
  1033. define method intersection-interval (range1 :: <bounded-range>,
  1034.                      range2 :: <unbounded-range>)
  1035.       => (x-from :: union (singleton (#f), <integer>),
  1036.       x-to :: union (singleton (#f), <integer>));
  1037.    let from1 = range1.range-from;
  1038.    let to1 = range1.last;
  1039.    let from2 = range2.range-from;
  1040.    select (range-directions (range1, range2))
  1041.       #"increasing-increasing" =>
  1042.      values (max (from1, from2), to1);
  1043.       #"increasing-decreasing" =>
  1044.      values (from1, min (to1, from2));
  1045.       #"decreasing-increasing" =>
  1046.      values (max (to1, from2), from1);
  1047.       #"decreasing-decreasing" =>
  1048.      values (to1, min (from1, from2));
  1049.    end select;
  1050. end method;
  1051. //
  1052. define method intersection-interval (range1 :: <unbounded-range>,
  1053.                      range2 :: <bounded-range>)
  1054.       => (x-from :: union (singleton (#f), <integer>),
  1055.       x-to :: union (singleton (#f), <integer>));
  1056.    let from1 = range1.range-from;
  1057.    let from2 = range2.range-from;
  1058.    let to2 = range2.last;
  1059.    select (range-directions (range1, range2))
  1060.       #"increasing-increasing" =>
  1061.      values (max (from1, from2), to2);
  1062.       #"increasing-decreasing" =>
  1063.      values (max (from1, to2), from2);
  1064.       #"decreasing-increasing" =>
  1065.      values (from2, min (from1, to2));
  1066.       #"decreasing-decreasing" =>
  1067.      values (to2, min (from1, from2));
  1068.    end select;
  1069. end method;
  1070. //
  1071. define method intersection-interval (range1 :: <unbounded-range>,
  1072.                      range2 :: <unbounded-range>)
  1073.       => (x-from :: union (singleton (#f), <integer>),
  1074.       x-to :: union (singleton (#f), <integer>));
  1075.    let from1 = range1.range-from;
  1076.    let from2 = range2.range-from;
  1077.    select (range-directions (range1, range2))
  1078.       #"increasing-increasing" =>
  1079.      values (max (from1, from2), #f);
  1080.       #"increasing-decreasing" =>
  1081.      values (from1, from2);
  1082.       #"decreasing-increasing" =>
  1083.      values (from2, from1);
  1084.       #"decreasing-decreasing" =>
  1085.      values (#f, min (from1, from2));
  1086.    end select;
  1087. end method;
  1088.